package top.cardone.security.shiro.realm.impl;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import top.cardone.context.ApplicationContextHolder;
import top.cardone.core.CodeException;
import top.cardone.core.util.func.Func1;
import top.cardone.security.shiro.authc.impl.OAuth2TokenImpl;

import java.util.Set;

/**
 * Created by yht on 16-2-2.
 */
@Log4j2
public class OAuth2RealmImpl extends AuthorizingRealm {
	@Setter
	@Getter
	private String readListRoleFuncName = StringUtils.EMPTY;

	@Setter
	@Getter
	private String readListPermissionFuncName = StringUtils.EMPTY;

	@Setter
	@Getter
	private String readCredentialsFuncName = StringUtils.EMPTY;

	@Override
	public boolean supports(AuthenticationToken token) {
		//仅支持 StatelessTokenImpl 类型的Token
		return token instanceof OAuth2TokenImpl;
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		//根据用户名查找角色，请根据需求实现
		String principal = (String) principals.getPrimaryPrincipal();

		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

		if (StringUtils.isNotBlank(readListRoleFuncName)) {
			authorizationInfo.setRoles((Set<String>) ApplicationContextHolder.func(Func1.class, func -> func.func(principal), readListRoleFuncName));
		}

		if (StringUtils.isNotBlank(readListPermissionFuncName)) {
			authorizationInfo.setStringPermissions((Set<String>) ApplicationContextHolder.func(Func1.class, func -> func.func(principal), readListPermissionFuncName));
		}

		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		OAuth2TokenImpl oauth2Token = (OAuth2TokenImpl) token;

		if (oauth2Token.getCredentials() == null || StringUtils.isBlank(oauth2Token.getCredentials().toString())) {
			throw new CodeException("000001", "凭证不能为空值!");
		}

		Object credentials;

		if (StringUtils.isNotBlank(readCredentialsFuncName)) {
			credentials = ApplicationContextHolder.func(Func1.class, func -> func.func(oauth2Token.getPrincipal()), readCredentialsFuncName);
		} else {
			credentials = oauth2Token.getCredentials();
		}

		//然后进行客户端消息摘要和服务器端消息摘要的匹配
		return new SimpleAuthenticationInfo(oauth2Token.getPrincipal(), credentials, getName());
	}
}